#include "map.h"
#include "exception.h"
#include "error.h"

#include "..\common\util.h"
#include "..\common\types.h"
#include "..\common\def.h"
#include "..\render\d3d.h"
#include "..\render\interface_types.h"
#include "..\physics\physics.h"
//#include "..\input\dinput.h"

//#include "..\common\util.h"
//#include "..\math\matrix.h"
#include "engine.h"
#define WORLD_VER	200

CMap::CMap(void)
{
	pMesh = NULL;
	m_pVertices = NULL;

	m_groupCount = 0;

	EE_ZEROMEMORY(&m_infoHeader, sizeof(MapHeader));
	EE_ZEROMEMORY(&m_infoGlobal, sizeof(MapGlobalInfo));
	EE_ZEROMEMORY(&m_fogInfo, sizeof(MapFogInfo));
	EE_ZEROMEMORY(&m_envInfo, sizeof(MapEnvInfo));
}

CMap::~CMap(void)
{ }

HRESULT CMap::Release(void)
{
	if(pMesh)
	{
		if(FAILED(pMesh->Release()))
			return false;

		if(FAILED(CEngine::getInstance()->getPhysics()->releaseWorld()))
			return false;

	}
	//m_pGroups = NULL;
	m_pVertices = NULL;
	m_groupCount = 0;

	EE_ZEROMEMORY(&m_infoHeader,  sizeof(MapHeader));
	EE_ZEROMEMORY(&m_infoGlobal,  sizeof(MapGlobalInfo));
	EE_ZEROMEMORY(&m_fogInfo,  sizeof(MapFogInfo));
	EE_ZEROMEMORY(&m_envInfo,  sizeof(MapEnvInfo));
	return 0;
}

void CMap::Draw(CCamera *pCamera)
{
	
	pMesh->Draw(MATRIX4X4F::identity, NULL, 1);
}

void CMap::Update(float dt)
{ }

bool CMap::readFace(FILE *filePtr, Vertex **faceVerticesPtr)
{
	Vertex vertexReadArray[3] = { NULL };

	try
	{
		if(!(faceVerticesPtr && filePtr)) throw CEngineException();

		fread(vertexReadArray, sizeof(Vertex) * 3, 1, filePtr);

		for(int i = 0; i < 3; i++)
		{
			//Vertex *vertexReadPtr = &vertexReadArray[i];

			memcpy(&faceVerticesPtr[i], &vertexReadArray[i], sizeof(Vertex));

			/*faceVerticesPtr[i]->position[0] = vertexReadPtr->position[0];
			faceVerticesPtr[i]->position[1] = vertexReadPtr->position[2];
			faceVerticesPtr[i]->position[2] = vertexReadPtr->position[1];

			faceVerticesPtr[i]->normal[0] = vertexReadPtr->normal[0];
			faceVerticesPtr[i]->normal[1] = vertexReadPtr->normal[2];
			faceVerticesPtr[i]->normal[2] = vertexReadPtr->normal[1];

			faceVerticesPtr[i]->texA[0] = -vertexReadPtr->tc[0];
			faceVerticesPtr[i]->texA[1] = -vertexReadPtr->tc[1];

			faceVerticesPtr[i]->texB[0] = vertexReadPtr->tc_lm[0];
			faceVerticesPtr[i]->texB[1] = -vertexReadPtr->tc_lm[1];*/
		}
	}
	catch(CEngineException)
	{
		return false;
	}

	return true;
}

//bool CMap::readGroup(FILE *filePtr, Group *groupPtr)
//{
//	int numFaces = 0;
//	int numVerts = 0;
//	VECTOR3F minmaxPoints[2] = {VECTOR3F()};
//
//	try
//	{
//		if(!(groupPtr && filePtr)) throw CEngineException();
//
//		fread(&numFaces, sizeof(int), 1, filePtr);
//
//		if(numFaces <= 0) throw CEngineException();
//
//		numVerts = numFaces * 3;
//
//		groupPtr->m_pVertices = EE_NEW Vertex[numVerts];
//		groupPtr->m_pIndicies = EE_NEW unsigned int[numVerts];
//		groupPtr->m_numIndicies = numVerts;
//		groupPtr->m_numVerts = numVerts;
//		groupPtr->m_numTriangles = numFaces;
//		groupPtr->m_numFrames = 1;
//
//		for(int faceIndex = 0, vIndex = 0; faceIndex < numFaces; faceIndex++, vIndex += 3)
//		{
//			Vertex	*faceVerticesPtr[3] =
//			{
//				&groupPtr->m_pVertices[vIndex + 0],
//				&groupPtr->m_pVertices[vIndex + 1],
//				&groupPtr->m_pVertices[vIndex + 2]
//			};
//
//			groupPtr->m_pIndicies[vIndex + 0] = vIndex + 2;
//			groupPtr->m_pIndicies[vIndex + 1] = vIndex + 1;
//			groupPtr->m_pIndicies[vIndex + 2] = vIndex + 0;
//
//			if(FAILED(readFace(filePtr, (Vertex **) &faceVerticesPtr))) throw CEngineException();
//		
//			//first bound box extreme
//			if(vIndex == 0)
//			{
//				minmaxPoints[0].x = minmaxPoints[1].x = faceVerticesPtr[0]->position[0];
//				minmaxPoints[0].y = minmaxPoints[1].y = faceVerticesPtr[0]->position[1];
//				minmaxPoints[0].z = minmaxPoints[1].z = faceVerticesPtr[0]->position[2];
//			}
//			checkBounds(faceVerticesPtr, minmaxPoints);	
//		}
//
//		groupPtr->m_minBB = minmaxPoints[0];
//		groupPtr->m_maxBB = minmaxPoints[1];
//	}
//
//	catch(CEngineException)
//	{
//		return false;
//	}
//
//	return true;
//}

//void CMap::checkBounds(Vertex **faceVerticesPtr, VECTOR3F* minmixPtr)
//{
//	Vertex *p0 = faceVerticesPtr[0];
//	Vertex *p1 = faceVerticesPtr[1];
//	Vertex *p2 = faceVerticesPtr[2];
//	
//	VECTOR3F *pMin = &minmixPtr[0];
//	VECTOR3F *pMax = &minmixPtr[1];
//	
//	if(p0->position[0] < pMin->position[0])			pMin->position[0] = p0->position[0];
//	else if(p0->position[0] > pMax->position[0])	pMax->position[0] = p0->position[0];
//
//	if(p0->position[1] < pMin->position[1])			pMin->position[1] = p0->position[1];
//	else if(p0->position[1] > pMax->position[1])	pMax->position[1] = p0->position[1];
//
//	if(p0->position[2] < pMin->position[2])			pMin->position[2] = p0->position[2];
//	else if(p0->position[2] > pMax->position[2])	pMax->position[2] = p0->position[2];
//	///////////////////
//	if(p1->position[0] < pMin->position[0])			pMin->position[0] = p1->position[0];
//	else if(p1->position[0] > pMax->position[0])	pMax->position[0] = p1->position[0];
//
//	if(p1->position[1] < pMin->position[1])			pMin->position[1] = p1->position[1];
//	else if(p1->position[1] > pMax->position[1])	pMax->position[1] = p1->position[1];
//
//	if(p1->position[2] < pMin->position[2])			pMin->position[2] = p1->position[2];
//	else if(p1->position[2] > pMax->position[2])	pMax->position[2] = p1->position[2];
//	///////////////////
//	if(p2->position[0] < pMin->position[0])			pMin->position[0] = p2->position[0];
//	else if(p2->position[0] > pMax->position[0])	pMax->position[0] = p2->position[0];
//
//	if(p2->position[1] < pMin->position[1])			pMin->position[1] = p2->position[1];
//	else if(p2->position[1] > pMax->position[1])	pMax->position[1] = p2->position[1];
//
//	if(p2->position[2] < pMin->position[2])			pMin->position[2] = p2->position[2];
//	else if(p2->position[2] > pMax->position[2])	pMax->position[2] = p2->position[2];
//}


void CMap::readTexture(FILE *filePtr, string *sz_texture, string *sz_normal)
{
	if(filePtr)
	{
		char	textureName[64];
		EE_ZEROMEMORY(textureName, sizeof(textureName));
		fread(textureName, sizeof(char) * 64, 1, filePtr);

		if(sz_texture)
			*sz_texture = string(textureName);
		else
			sz_texture = NULL;

		char	normalName[64];
		EE_ZEROMEMORY(normalName, sizeof(normalName));
		fread(normalName, sizeof(char) * 64, 1, filePtr);

		if(sz_normal)
			*sz_normal = string(normalName);
		else
			sz_normal = NULL;
	}
	else
	{
		sz_texture = NULL;
		sz_normal = NULL;
	}
}

//bool CMap::buildVertexArray(Vertex **vertexArrayPtr, unsigned int **indiceArrayPtr, 
//							   unsigned int totalVertexCount, Group *groupPtr, unsigned int groupCount)
//{
//	unsigned int		vArryIdx = 0, iArryIdx = 0;
//
//	Vertex	*vArrayPtr = NULL;
//	unsigned int		*iArrayPtr = NULL;
//
//	try
//	{
//		if(*vertexArrayPtr || *indiceArrayPtr) throw CEngineException();
//		if(!groupPtr) throw CEngineException();
//		if(totalVertexCount == 0 || groupCount == 0) throw CEngineException();
//
//		vArrayPtr = EE_NEW Vertex[totalVertexCount];
//		if(!vArrayPtr) throw CEngineException();
//
//		iArrayPtr = EE_NEW unsigned int[totalVertexCount];
//		if(!iArrayPtr) throw CEngineException();
//
//		for(int g = 0; g < groupCount; g++)
//		{
//			Group	*pG = &groupPtr[g];
//
//			if(pG->m_numVerts > 0)
//			{
//				pG->m_vertArrayBaseIdx = vArryIdx;
//
//				for(unsigned int gv = 0; gv < pG->m_numVerts; gv += 3)
//				{
//					vArrayPtr[vArryIdx + 0] = pG->m_pVertices[gv + 0];
//					vArrayPtr[vArryIdx + 1] = pG->m_pVertices[gv + 1];
//					vArrayPtr[vArryIdx + 2] = pG->m_pVertices[gv + 2];
//					vArryIdx += 3;
//				}
//				
//				//EE_SAFEDELETEARRAY(pG->m_pVertices) 
//				//pG->m_pVertices = &vArrayPtr[vArryIdx - pG->m_numVerts];
//			}
//
//			if(pG->m_numIndicies > 0)
//			{
//				for(unsigned int gi = 0; gi < pG->m_numIndicies; gi++)
//				{
//					iArrayPtr[iArryIdx] = pG->m_pIndicies[gi];
//					iArryIdx++;
//				}
//
//				//EE_SAFEDELETEARRAY(pG->m_pIndicies) 
//				//pG->m_pIndicies = &iArrayPtr[iArryIdx - pG->m_numIndicies];
//			}
//		}
//
//		*vertexArrayPtr = vArrayPtr;
//		*indiceArrayPtr = iArrayPtr;
//	}
//
//	catch(CEngineException)
//	{
//		EE_SAFEDELETEARRAY(vArrayPtr);
//		EE_SAFEDELETEARRAY(iArrayPtr);
//
//		*vertexArrayPtr = NULL;
//		*indiceArrayPtr = NULL;
//		return false;
//	}
//
//	return true;
//}

bool CMap::readObjects(FILE *filePtr)
{
	int entityCount = 0;
	int lightCount = 0;
	try
	{
		if(!filePtr) throw CEngineException();

		fread(&entityCount, sizeof(int), 1, filePtr);

		if(entityCount > 0)
		{
			entityCount = entityCount - 1;

			for(int i = 0; i < entityCount; i++)
			{
				worldEntity entityInfo;
				fread(&entityInfo, sizeof(worldEntity), 1, filePtr);

				CObject *mapObjectPtr = NULL;
				if(SUCCEEDED(objectInterpreter(entityInfo, &mapObjectPtr))) 
				{
					CEngine::getInstance()->registerObject(mapObjectPtr);
				}
			}
		}

		fread(&lightCount, sizeof(int), 1, filePtr);
		if(lightCount > 0)
		{
			for(int i = 0; i < lightCount; i++)
			{
				worldLightEntity	lightInfo;
				fread(&lightInfo, sizeof(worldLightEntity), 1, filePtr);

				CObject *mapLightPtr = NULL;
				if(SUCCEEDED(objectInterpreter(lightInfo, &mapLightPtr))) 
				{
					CEngine::getInstance()->registerObject(mapLightPtr);
				}
			}
		}
	}

	catch(CEngineException)
	{
		return false;
	}

	return true;
}

HRESULT CMap::loadMapData(string &sz_filename)
{
	//FILE			*filePtr = NULL;
	//MapHeader		infoHeader;
	//MapGlobalInfo	infoGlobal;
	//MapFogInfo		fogInfo;
	//MapEnvInfo		envInfo;

	//int				groupCount = 0;
	//int				indiceCount = 0;
	//int				totalVertexCount = 0;
	//Group			*pGroups = NULL;
	//Vertex		*pVertices = NULL;
	//unsigned int			*pIndices = NULL;

	//try
	//{

	//	/* Open file and read header data */
	//	filePtr = CEngine::getInstance()->findFile(sz_filename);
	//	if(!filePtr) throw CEngineException("Could not open file: " + sz_filename);

	//	fread(&infoHeader, sizeof(MapHeader), 1, filePtr);
	//	if(infoHeader.version != WORLD_VER)
	//		throw CEngineException("World file " + sz_filename + " has unknown version");

	//	fread(&infoGlobal, sizeof(MapGlobalInfo), 1, filePtr);
	//	fread(&fogInfo, sizeof(MapFogInfo), 1, filePtr);
	//	fread(&envInfo, sizeof(MapEnvInfo), 1, filePtr);

	//	/* Read D3DTexture2D filenames */
	//	fread(&groupCount, sizeof(int), 1, filePtr);

	//	if(infoHeader.hasLightMap)	/* Lightmap introduces additional D3DTexture2D/group */
	//		groupCount--;
	//	if(groupCount < 1) throw CEngineException("Bad group count in: " + sz_filename);

	//	pGroups = EE_NEW Group[groupCount];
	//	if(!pGroups) throw CEngineException("Out of memory");
	//	for(int i = 0; i < groupCount; i++) readTexture(filePtr, &pGroups[i].m_TextureName, NULL);

	//	if(infoHeader.hasLightMap)
	//	{
	//		std::string	lightmapName;
	//		readTexture(filePtr, &lightmapName, NULL);
	//		for(int i = 0; i < groupCount; i++) pGroups[i].m_LightmapName = lightmapName;
	//	}

	//	for(int i = 0; i < groupCount; i++)
	//	{
	//		if(FAILED(readGroup(filePtr, &pGroups[i]))) throw CEngineException("Mesh data appears corrupt");

	//		totalVertexCount += pGroups[i].m_numVerts;
	//		indiceCount += pGroups[i].m_numIndicies;
	//	}

	//	/* Organsize mesh data */
	//	if(FAILED(buildVertexArray(&pVertices, &pIndices, totalVertexCount, pGroups, groupCount)))
	//		throw CEngineException("Failed to organize mesh data");

	//	if(FAILED(CEngine::getInstance()->getPhysics()->createWorld(pGroups,groupCount)))
	//		throw CEngineException("Failed to create physical world");

	//	if(FAILED(readObjects(filePtr))) throw CEngineException("Failed to read map objects");

	//	fclose(filePtr);

	//	m_pGroups = pGroups;
	//	m_pVertices = pVertices;
	//	m_groupCount = groupCount;
	//}

	//catch(CEngineException e)
	//{
	//	EE_ERROR(e.getMessage());
	//	EE_ZEROMEMORY(&infoHeader, 0, sizeof(MapHeader));
	//	EE_ZEROMEMORY(&infoGlobal, 0, sizeof(MapGlobalInfo));
	//	EE_ZEROMEMORY(&fogInfo, 0, sizeof(MapFogInfo));
	//	EE_ZEROMEMORY(&envInfo, 0, sizeof(MapEnvInfo));

	//	if(filePtr) fclose(filePtr);

	//	EE_SAFEDELETEARRAY(m_pGroups);
	//	EE_SAFEDELETEARRAY(m_pVertices);
	//	m_groupCount = 0;

	//	EE_SAFEDELETEARRAY(pGroups) 
	//		EE_SAFEDELETEARRAY(pVertices) 
	//		EE_SAFEDELETEARRAY(pIndices) 
	//		return false;
	//}

	return true;
}

HRESULT CMap::Load(string &sz_filename)
{
	try
	{
		if(sz_filename.length() == 0) 
			throw EE_EXCEPTION("Invalid map filename");

		if(FAILED(Release())) 
			throw EE_EXCEPTION("Failed to unload map");

		Vertex	*pVerts = NULL;
		VECTOR3F	*pNormals = NULL;

		unsigned int		*pNumVerts = NULL;
		unsigned int		*pNumPrims = NULL;

		string		*pTextures = NULL;

		unsigned int		numSubsets = 0;
		unsigned int		numVerts = 0;

		if(FAILED(loadMapData(sz_filename))) throw CEngineException("Failed to load map");

		m_Identity = CUtil::getFilename(sz_filename);

		//CEngine::getInstance()->getRenderer()->setFogParameters(COLOR3F(1,0,0), 0.5);
		//pMesh = CEngine::getInstance()->getRenderer()->createMesh(m_Identity, m_pGroups, m_groupCount, m_pVertices);

		return S_OK;
	}
	catch(CError::CErrorData error)
	{
		CError::CError(error);
		return E_FAIL;
	}

	
}
